#include <QDir>
#ifdef QY_USE_QSETTINGS_FOR_LEXERFACTORY
#include <QSettings>
#endif/*QY_USE_QSETTINGS_FOR_LEXERFACTORY*/
#include <QDebug>
#include <Qsci/qscilexer.h>

#include "QyLexerFactory.h"

/**************************************************************************************************/

QMap<QString,QyLexerFactory*> QyLexerFactory::p_factories;
QList<QyLexerFactory*> QyLexerFactory::p_deadFactories;
bool QyLexerFactory::p_deleteOldFactories = true;

/**************************************************************************************************/
#ifdef QY_USE_QSETTINGS_FOR_LEXERFACTORY
class QyLexerSettings : public QsciLexer {
public:
    const char * language() const { return 0; }
    const char * lexer() const { return 0; }
    QString description(int) const { return QString(); }

	static bool writeSettings( QsciLexer * lexer, QSettings & settings, const QString & prefix );
	static bool readSettings( QsciLexer * lexer, QSettings & settings, const QString & prefix );

};

bool QyLexerSettings::writeSettings( QsciLexer * lexer, QSettings & qs,
	const QString & prefix )
{

    bool rc = true;
    QString key, fmt("%1");
    QStringList fdesc;

    // setStyleDefaults();

    // Write the styles.
    for ( int i=0; i<128; ++i ) {

        // Ignore invalid styles.
        if ( lexer->description(i).isEmpty() )
            continue;

        QColor c;

        key.sprintf( "%s/%s/style%d/", prefix.toStdString().c_str(), lexer->language(), i );

        // Write the foreground colour.

        qs.setValue( key + "color", lexer->color(i).name() );

        // Write the end-of-line fill.
        qs.setValue( key + "eolfill", lexer->eolFill(i) );

        // Write the font
        QFont f = lexer->font(i);

        fdesc.clear();
        fdesc += f.family();
        fdesc += fmt.arg( f.pointSize() );

        // The casts are for Borland.
        fdesc += fmt.arg( (int) f.bold() );
        fdesc += fmt.arg( (int) f.italic() );
        fdesc += fmt.arg( (int) f.underline() );

        qs.setValue( key + "font", fdesc );

        // Write the background colour.

        qs.setValue( key + "paper", lexer->paper(i).name() );
    }

    // Write the properties.
	key.sprintf( "%s/%s/properties/", prefix.toStdString().c_str(), lexer->language() );

    // Write the rest.
    key.sprintf( "%s/%s/", prefix.toStdString().c_str(), lexer->language() );

    // Write the default foreground colour.
    qs.setValue( key + "defaultcolor", lexer->defaultColor().name() );

    // Write the default background colour.
    qs.setValue( key + "defaultpaper", lexer->defaultPaper().name() );

    // Write the default font
	QFont defFont( lexer->defaultFont() );

    fdesc.clear();
    fdesc += defFont.family();
    fdesc += fmt.arg( defFont.pointSize() );

    // The casts are for Borland.
    fdesc += fmt.arg( (int) defFont.bold() );
    fdesc += fmt.arg( (int) defFont.italic() );
    fdesc += fmt.arg( (int) defFont.underline() );

    qs.setValue( key + "defaultfont", fdesc );
    qs.setValue( key + "autoindentstyle", lexer->autoIndentStyle() );

    return rc;
}

bool QyLexerSettings::readSettings( QsciLexer * lexer, QSettings & qs,
	const QString & prefix )
{

	bool ok, flag, rc = true;
    QString key, full_key, colorName;
    QStringList fdesc;

    // !!! lexer->setStyleDefaults();


    // Read the properties.
    key.sprintf( "%s/%s/properties/", prefix.toStdString().c_str(), lexer->language() );

    lexer->refreshProperties();

    // Read the rest.
    key.sprintf( "%s/%s/", prefix.toStdString().c_str(), lexer->language() );

    // Read the default foreground colour.
    full_key = key + "defaultcolor";

    ok = qs.contains(full_key);
    colorName = qs.value(full_key).toString();

    if (ok)
        lexer->setDefaultColor( QColor(colorName) );
    else
        rc = false;

    // Read the default background colour.
    full_key = key + "defaultpaper";

    ok = qs.contains(full_key);
    colorName = qs.value(full_key).toString();

    if (ok)
        lexer->setDefaultPaper( QColor(colorName) );
    else
        rc = false;

    // Read the default font.
    full_key = key + "defaultfont";

    ok = qs.contains(full_key);
    fdesc = qs.value(full_key).toStringList();

    if ( ok && fdesc.count() == 5 ) {

        QFont f;

        f.setFamily(fdesc[0]);
        f.setPointSize( fdesc[1].toInt() );
        f.setBold( fdesc[2].toInt() );
        f.setItalic( fdesc[3].toInt() );
        f.setUnderline( fdesc[4].toInt() );

        lexer->setDefaultFont(f);

    } else
        rc = false;

    full_key = key + "autoindentstyle";

    ok = qs.contains(full_key);

    if (ok)
        lexer->setAutoIndentStyle( qs.value(full_key).toInt() );
    else
        rc = false;

    // Read the styles.
    for ( int i=0; i<128; ++i ) {

        // Ignore invalid styles.
        if ( lexer->description(i).isEmpty() )
            continue;

        key.sprintf( "%s/%s/style%d/", prefix.toStdString().c_str(), lexer->language(), i );

        // Read the foreground colour.
        full_key = key + "color";

        ok = qs.contains(full_key);
        colorName = qs.value(full_key).toString();

        if (ok)
            lexer->setColor( QColor(colorName), i );
        else
            lexer->setColor( lexer->defaultColor(), i );

        // Read the end-of-line fill.
        full_key = key + "eolfill";

        ok = qs.contains(full_key);
        flag = qs.value( full_key, false ).toBool();

        if (ok)
            lexer->setEolFill( flag, i );
        else
            lexer->setEolFill( false, i );

        // Read the font
        full_key = key + "font";

        ok = qs.contains(full_key);
        fdesc = qs.value(full_key).toStringList();

        if ( ok && fdesc.count() == 5 ) {

            QFont f;

            f.setFamily(fdesc[0]);
            f.setPointSize( fdesc[1].toInt() );
            f.setBold( fdesc[2].toInt() );
            f.setItalic( fdesc[3].toInt() );
            f.setUnderline( fdesc[4].toInt() );

            lexer->setFont( f, i );

        } else {

            lexer->setFont( lexer->defaultFont(), i );

		}

        // Read the background colour.
        full_key = key + "paper";

        ok = qs.contains(full_key);
        colorName = qs.value(full_key).toString();

        if (ok)
            lexer->setPaper( QColor(colorName), i );
        else
            lexer->setPaper( lexer->defaultPaper(), i );

    }

    return rc;
}

#endif/*QY_USE_QSETTINGS_FOR_LEXERFACTORY*/
/**************************************************************************************************/

QyLexerFactory::QyLexerFactory( const QString & fileFilter ) {

	p_fileFilter = fileFilter;

	if ( p_factories.contains(fileFilter) ) {

		if (p_deleteOldFactories)
			delete p_factories[p_fileFilter];
		else
			p_deadFactories.append(p_factories[p_fileFilter]);

	}

	p_factories[p_fileFilter] = this;

}

QyLexerFactory::~QyLexerFactory() {

	p_factories.remove(p_fileFilter);

}

QString QyLexerFactory::displayName() const {

	if ( QsciLexer * l = lexer() )
		return l->language();

	return p_fileFilter;
}

// QString QyLexerFactory::nameWithoutSpace() const {

	// QString name( displayName().simplified() );

	// return name.replace( " ", "_" );
// }

bool QyLexerFactory::match( const QString & fileName ) const {

	return QDir::match( p_fileFilter, fileName );
}

QsciLexer * QyLexerFactory::lexer() const {

	return 0;
}

#ifdef QY_USE_QSETTINGS_FOR_LEXERFACTORY

void QyLexerFactory::restoreLexerSettings( QSettings & settings,
	const QString & prefix )
{

	QsciLexer * l = lexer();

	if (!l)
		return;

	// qDebug() << "prefix" << prefix;

	if ( !QyLexerSettings::readSettings( l, settings, prefix.toStdString().c_str() ) )
		qWarning("Lexer settings not loaded.");

}

void QyLexerFactory::saveLexerSettings( QSettings & settings, const QString & prefix ) {

	QsciLexer * l = lexer();

	if (!l)
		return;

	if ( !QyLexerSettings::writeSettings( l, settings, prefix.toStdString().c_str() ) )
		qWarning("Lexer settings not writed.");

}

#endif/*QY_USE_QSETTINGS_FOR_LEXERFACTORY*/

QList<QyLexerFactory*> QyLexerFactory::factories() {

	return p_factories.values();
}

QsciLexer * QyLexerFactory::lexer( const QString & fileName ) {

	QList<QyLexerFactory*> factories( p_factories.values() );

	foreach ( QyLexerFactory * factory, factories ) {

		if ( factory->match(fileName) ) {

			p_deleteOldFactories = false;
			return factory->lexer();
		}

	}

	return 0;
}

QsciLexer * QyLexerFactory::lexerByFilefilter( const QString & fileFilter ) {

	return p_factories.contains(fileFilter) ? p_factories[fileFilter]->lexer() : 0;
}

void QyLexerFactory::deleteOldFactories() {

	foreach ( QyLexerFactory * factory, p_deadFactories )
		delete factory;

	p_deadFactories.clear();
	p_deleteOldFactories = true;

}

void QyLexerFactory::clear() {

	deleteOldFactories();

	QList<QyLexerFactory*> factories( p_factories.values() );

	foreach ( QyLexerFactory * factory, factories )
		delete factory;

	p_factories.clear();

}

#ifdef QY_USE_QSETTINGS_FOR_LEXERFACTORY

void QyLexerFactory::restoreLexersSettings( QSettings & settings,
	const QString & prefix )
{

	QList<QyLexerFactory*> factories( p_factories.values() );

	foreach ( QyLexerFactory * factory, factories )
		factory->restoreLexerSettings( settings, prefix );

}

void QyLexerFactory::saveLexersSettings( QSettings & settings, const QString & prefix ) {

	QList<QyLexerFactory*> factories( p_factories.values() );

	foreach ( QyLexerFactory * factory, factories )
		factory->saveLexerSettings( settings, prefix );

}

#endif/*QY_USE_QSETTINGS_FOR_LEXERFACTORY*/
